#include <Ogre.h>
#include <OIS/OIS.h>
using namespace Ogre;

#include "MarbleMax.h"

Marble_Max::Marble_Max() /*: mOFManager(0)*/
{
}
Marble_Max::~Marble_Max()
{
	delete Root::getSingletonPtr();
	//OgreNewt::Debugger::getSingleton().deInit();
}
void Marble_Max::go()
{
	if (!initialise()) // start game
		return;

	Root::getSingletonPtr()->startRendering(); // start the render loop

	// clean up
	destroyScene(); // destroy everything
}
bool Marble_Max::initialise()
{
	new Root(); // create ogre root

	addResourceLocations(); // add resources

	// if we cannot initialise Ogre kill application
	if ( !initOgreCore() ) return false;

	if(!createSceneManager()) // create scene manager
		return false;
	mSceneMgr = Root::getSingletonPtr()->getSceneManager("MarbleManager"); // set current scene as the game scene

	if(!createCamera())
		return false;
	if(!createViewports()) // create viewports
		return false;

	// Set default mipmap level
	TextureManager::getSingleton().setDefaultNumMipmaps(5);

	// Create any resource listeners (for loading screens)
	createResourceListener();
	// Initialise resources
	initResources();

	// Create the scene
	if(!createScene())
		return false;

	if(!createFrameListener()) // create frame listener
		return false;

	return true;
}
void Marble_Max::addResourceLocations()
{
	// Load resource paths from config file
	ConfigFile cf;
	cf.load("resources.cfg");

	// Go through all sections & settings in the file
	ConfigFile::SectionIterator seci = cf.getSectionIterator();

	String secName, typeName, archName;
	while (seci.hasMoreElements())
	{
		secName = seci.peekNextKey();
		ConfigFile::SettingsMultiMap *settings = seci.getNext();
		ConfigFile::SettingsMultiMap::iterator i;
		for (i = settings->begin(); i != settings->end(); ++i)
		{
			typeName = i->first;
			archName = i->second;
			ResourceGroupManager::getSingleton().addResourceLocation(
			archName, typeName, secName);
		}
	}
}
bool Marble_Max::initOgreCore()
{
	// Show the configuration dialog and initialise the system
	/*if(!Root::getSingletonPtr()->restoreConfig())//user clicked okay
	{*/
		if(Root::getSingletonPtr()->showConfigDialog())
		{
			#ifndef _DEBUG
				mWindow = Root::getSingletonPtr()->initialise(true,"MarbleMax"); // create the window
			#else
				mWindow = Root::getSingletonPtr()->initialise(true,"MarbleMax DEBUG"); //  create the window
			#endif
		return true;
		}
		else
		{
			return false;
		}
	/*}
	else//user clicked cancel
	{
		mWindow = Root::getSingletonPtr()->initialise(true);
		return true;
	}*/
}
bool Marble_Max::createSceneManager()
{
	// Create a exterior for play
	mSceneMgr = Root::getSingletonPtr()->createSceneManager(ST_EXTERIOR_CLOSE,"MarbleManager");

	// Create generic for GUI
	mSceneMgr = Root::getSingletonPtr()->createSceneManager(ST_GENERIC,"GUIMenu");

	// current game state (menu or play)
	currGameState = BUILDSTATE;
	currBuildMode = BM_BUILD;
	return true;
}
bool Marble_Max::createViewports()
{
	// Create one viewport
	mainView = mWindow->addViewport(mCamera); // add mainView as the window's viewport
	mainView->setBackgroundColour(ColourValue(0.8,0.8,0.8)); // set the background colour to black

	// Alter the camera aspect ratio to match the viewport
	mCamera->setAspectRatio(Real(mainView->getActualWidth()) / Real(mainView->getActualHeight()));
	return true;
}
bool Marble_Max::createResourceListener()
{
	return true;
}
void Marble_Max::initResources()
{
	//mOFManager = new ObjectFileManager();
	ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}
bool Marble_Max::createScene()
{
	if(!createGUI())
		return false;
	if(!createMarbleScene())
		return false;
	/*if(!createMenuScene()) // create the menu
		return false;*/
	// for now, just create the play scene, then let Mason create all the menus and such
	return true;
}
bool Marble_Max::createFrameListener()
{
	mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay"); // get Ogre's debug overlay
	OverlayManager::getSingleton().destroyOverlayElement("Core/LogoPanel");	// remove the ogre graphic in the bottom right of the screen
	mDebugOverlay->show(); // show the overlay
	
	statCFPS = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps"); // set current fps pointer
	statAFPS = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps"); // set average fps pointer
	statLoc = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps");	// set location pointer
	statDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText"); // set debug string pointer
	
	if(!createInputListener(mWindow)) // create the input listener (OIS)
		return false;

	mOgreNewtListener = new OgreNewt::BasicFrameListener(mWindow,mSceneMgr,mWorld,60);

	mBall = new Marble(mSceneMgr,Vector3(10,30,10));

	Root::getSingletonPtr()->addFrameListener(this); // add this class as a frame listener
	Root::getSingletonPtr()->addFrameListener(mOgreNewtListener);
	return true;
}
bool Marble_Max::createMarbleScene()
{
	mSceneMgr = Root::getSingletonPtr()->getSceneManager("MarbleManager"); // get the play scene manager

	if(!initGame()) // initialise game stuffs
		return false;
	//if(!createCamera()) // create the camera
	//	return false;

	// set the mood
	mSceneMgr->setAmbientLight(ColourValue(.5, .5, .5));
	mSceneMgr->setSkyDome(true,"SkyCloudy",5,8);

	/*/ Floor
	Plane plane(Vector3::UNIT_Y,0);
	MeshManager::getSingletonPtr()->createPlane("FloorType",ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,2000,2000,25,25,true,1,5,5,Vector3::UNIT_Z);
	Entity* ent = mSceneMgr->createEntity("Floor","FloorType");
	//mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
	ent->setCastShadows(false);
	ent->setMaterialName("Floor");
	Ogre::StaticGeometry* sg = mSceneMgr->createStaticGeometry("WorldFloor");
	sg->addEntity(ent,Vector3::ZERO);/**/

	mSceneMgr->setWorldGeometry("Beta.cfg");

	//camera settings
	camNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,5,10)); // create the main camera node
	camYawNode = camNode->createChildSceneNode(); // create the yaw node (left-right)
	camPitchNode = camYawNode->createChildSceneNode(); // create the pitch node (up-down)
	camPitchNode->attachObject(mCamera); // attach camera to pitch node
	camPitchNode->pitch(Degree(-30));

	createTrackPieces();

	mouseNode = mSceneMgr->getSceneNode("NORMALNODE");

	//Entity entpiece("TrackNormal","StraightTrack.mesh");

	mWorld = new OgreNewt::World();
	mWorld->setWorldSize(Vector3(0,0,0),Vector3(1500,500,1500));
	mWorld->setFrictionModel(OgreNewt::World::FrictionModelMode::FM_ADAPTIVE);
	mWorld->setSolverModel(OgreNewt::World::SolverModelMode::SM_ADAPTIVE);
	
	OgreNewt::MaterialID *track = new OgreNewt::MaterialID(mWorld,0);
	OgreNewt::MaterialID *ball = new OgreNewt::MaterialID(mWorld,1);
	OgreNewt::MaterialPair *friction = new OgreNewt::MaterialPair(mWorld,track,ball);
	friction->setDefaultFriction(.5,.5);

	mRaySceneQuery = mSceneMgr->createRayQuery(Ray());

	Entity* ent = mSceneMgr->createEntity("Plane",SceneManager::PT_PLANE);
	ent->setMaterialName("Floor");
	SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
	node->attachObject(ent);
	node->setScale(.1,.1,.1);
	node->pitch(Radian(Math::PI/2));
	node->setPosition(10,1,10);

	return true;
}
bool Marble_Max::initGame()
{
	// game stuffs
	mMoveSpeed = 100;					// set movement speed to 100 units per second
	mMoveScale = 0.0f;					// for first frame, set move speed per frame to 0
	mTranslateVector = Vector3::ZERO;	// set movement vector to a zero vector (not moving)
	mMoveVector = Vector3::ZERO;		// set movement direction to a zero vector (not moving)
	mRotSpeed = 36;						// set rotate speed to 36 degrees per second, full rotation in 10 seconds
	mRotScale = 0.0f;					// for first frame, set rotate speed per frame to 0
	mRightMDown = false;				// the right mouse button is probly not being held down yet
	mRightMUp = false;
	mLeftMDown = false;
	mLeftMUp = false;
	numObjects = 0;
	mouseLoc = Vector2::ZERO;
	objectHeight = 0;
	mCurrTrack = NORMAL;
	numBalls = 0;

	for(int i = 0; i < 150; i++)
	{
		for(int j = 0; j < 20; j++)
		{
			for(int k = 0; k < 150; k++)
			{
				space[i][j][k] = true;
			}
		}
	}

	return true;
}
bool Marble_Max::createCamera()
{
	// Create the camera
	mCamera = mSceneMgr->createCamera("PlayerCam"); // create the player's camera
	mCamera->setNearClipDistance(1); // set nearclipdistance to 1, making so camera does not render things too close to itself
	return true;
}
bool Marble_Max::createTrackPieces()
{
	SceneNode *node;
	Entity *entity;
	
	// NORMAL
	node = mSceneMgr->getRootSceneNode()->createChildSceneNode("NORMALNODE");
	entity = mSceneMgr->createEntity("NORMALMESH","NormalTrack.mesh");
	node->attachObject(entity);
	node->scale(10,10,10);
	node->rotate(Quaternion(Radian(Math::PI),Vector3(0,0,1)));
	node->showBoundingBox(true);

	node = mSceneMgr->getRootSceneNode()->createChildSceneNode("DOUBLENODE");
	entity = mSceneMgr->createEntity("DOUBLEMESH","DoubleTrack.mesh");
	node->attachObject(entity);
	node->scale(10,10,10);
	node->rotate(Quaternion(Radian(Math::PI),Vector3(0,0,1)));
	node->setVisible(false);

	node = mSceneMgr->getRootSceneNode()->createChildSceneNode("SINGLENODE");
	entity = mSceneMgr->createEntity("SINGLEMESH","SingleTrack.mesh");
	node->attachObject(entity);
	node->scale(10,10,10);
	node->rotate(Quaternion(Radian(Math::PI),Vector3(0,0,1)));
	node->setVisible(false);
	
	node = mSceneMgr->getRootSceneNode()->createChildSceneNode("HALFNODE");
	entity = mSceneMgr->createEntity("HALFMESH","HalfTrack.mesh");
	node->attachObject(entity);
	node->scale(10,10,10);
	node->rotate(Quaternion(Radian(Math::PI),Vector3(1,0,0)));
	node->setVisible(false);

	node = mSceneMgr->getRootSceneNode()->createChildSceneNode("SHARPNODE");
	entity = mSceneMgr->createEntity("SHARPMESH","SharpTurnTrack.mesh");
	node->attachObject(entity);
	node->scale(10,10,10);
	node->rotate(Quaternion(Radian(Math::PI),Vector3(0,0,1)));
	node->setVisible(false);

	node = mSceneMgr->getRootSceneNode()->createChildSceneNode("BULLDOZENODE");
	entity = mSceneMgr->createEntity("BULLDOZEMESH","NormalTrack.mesh");
	node->attachObject(entity);
	node->scale(10,10,10);
	node->rotate(Quaternion(Radian(Math::PI),Vector3(0,0,1)));
	node->setVisible(false);
	
	return true;
}

/*
bool Marble_Max::createMenuScene()
{
	mSceneMgr = Root::getSingletonPtr()->getSceneManager("GUIMenu"); // get the menu scene manager
	mSceneMgr->setAmbientLight(ColourValue(1,0,0)); // set ambient light to red

	menuCam = mSceneMgr->createCamera("MenuCamera"); // create the menu camera

	if(!createGUI()) // create the GUI
		return false;
	
	if(!createMenu()) // create the menu
		return false;

	return true;
}
bool Marble_Max::createGUI()
{
	return true;
}
bool Marble_Max::createMenu()
{
	return true;
}
bool Marble_Max::createHUD()
{
	return true;
}*/